/*
 * entry.S - Entry point to system mode from user mode
 */

#include <asm.h>
#include <segment.h>
#include <errno.h>


/**************************************************/
/**** Save & Restore ******************************/
/**                                              **/
/** When we change to privilege level 0 (kernel) **/
/** (through an interrupt, a system call, an     **/
/** exception ...) we must save the state of the **/
/** currently running task (save).               **/
/**                                              **/
/** Stack layout in 'systemCall':                **/
/**                                              **/
/**   0(%esp) - %ebx    \                        **/
/**   4(%esp) - %ecx     |                       **/
/**   8(%esp) - %edx     |                       **/
/**   C(%esp) - %esi     | Register saved        **/
/**  10(%esp) - %edi     |  by 'save'            **/
/**  14(%esp) - %ebp     |                       **/
/**  18(%esp) - %eax     |                       **/
/**  1C(%esp) - %ds      |                       **/
/**  20(%esp) - %es      |                       **/
/**  24(%esp) - %fs      |                       **/
/**  28(%esp) - %gs     /                        **/
/**  2C(%esp) - %eip    \                        **/
/**  30(%esp) - %cs      |                       **/
/**  34(%esp) - %eflags  |  Return context saved **/
/**  38(%esp) - %oldesp  |   by the processor.   **/
/**  3C(%esp) - %oldss  /                        **/
/**                                              **/
/**************************************************/

#define SYS_LENGHT 41

#define SAVE_ALL \
      pushl %gs; \
      pushl %fs; \
      pushl %es; \
      pushl %ds; \
      pushl %eax; \
      pushl %ebp; \
      pushl %edi; \
      pushl %esi; \
      pushl %edx; \
      pushl %ecx; \
      pushl %ebx; \
      movl $__KERNEL_DS, %edx;    \
      movl %edx, %ds;           \
      movl %edx, %es;

#define RESTORE_ALL \
      popl %ebx; \
      popl %ecx; \
      popl %edx; \
      popl %esi; \
      popl %edi; \
      popl %ebp; \
      popl %eax; \
      popl %ds; \
      popl %es; \
      popl %fs; \
      popl %gs;

#define EOI		\
      movb $0x20, %al;  \
      outb %al, $0x20;

//Taula de Syscalls
ENTRY(sys_call_table)
	.long sys_ni_syscall
	.long sys_exit            //1
	.long sys_fork            //2
	.long sys_read            //3
	.long sys_write           //4
  .long sys_open            //5
	.long sys_close           //6
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
  .long sys_unlink          //10
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
  .long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
  .long sys_getpid          //20
	.long sys_sem_init        //21
	.long sys_sem_wait        //22
	.long sys_sem_signal      //23
	.long sys_sem_destroy     //24
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_ni_syscall
	.long sys_nice            //34
	.long sys_get_stats       //35
  .long sys_ni_syscall
  .long sys_ni_syscall
  .long sys_ni_syscall
  .long sys_ni_syscall
  .long sys_ni_syscall
  .long sys_dup             //41


//excepcions

ENTRY(divide_error_handler) //0
	SAVE_ALL
	call divide_error_routine
	RESTORE_ALL
	IRET

ENTRY(debug_handler) //1
	SAVE_ALL
	call debug_routine
	RESTORE_ALL
	IRET

ENTRY(nm1_handler)
	SAVE_ALL
	call nm1_routine
	RESTORE_ALL
	IRET

ENTRY(breakpoint_handler)//3
	SAVE_ALL
	call breakpoint_routine
	RESTORE_ALL
	IRET

ENTRY(overflow_handler)//4
	SAVE_ALL
	call overflow_routine
	RESTORE_ALL
	IRET

ENTRY(bounds_check_handler)//5
	SAVE_ALL
	call bounds_check_routine
	RESTORE_ALL
	IRET

ENTRY(invalid_opcode_handler)//6
	SAVE_ALL
	call invalid_opcode_routine
	RESTORE_ALL
	IRET

ENTRY(device_not_avaible_handler) //7
	SAVE_ALL
	call device_not_avaible_routine
	RESTORE_ALL
	IRET

ENTRY(double_fault_handler)//8
	SAVE_ALL
	call double_fault_routine
	RESTORE_ALL
	addl $4, %esp
	IRET

ENTRY(coprocessor_segment_overrun_handler)//9
	SAVE_ALL
	call coprocessor_segment_overrun_routine
	RESTORE_ALL
	IRET

ENTRY(invalid_tss_handler)//10
	SAVE_ALL
	call invalid_tss_routine
	RESTORE_ALL
	addl $4, %esp
	IRET

ENTRY(segment_not_present_handler)//11
	SAVE_ALL
	call segment_not_present_routine
	RESTORE_ALL
	addl $4, %esp
	IRET

ENTRY(stack_segment_handler) //12
	SAVE_ALL
	call stack_segment_routine
	RESTORE_ALL
	addl $4, %esp
	IRET

ENTRY(general_protection_handler)//13
	SAVE_ALL
	call general_protection_routine
	RESTORE_ALL
	addl $4, %esp
	IRET

ENTRY(page_fault_handler)//14
	SAVE_ALL
	call page_fault_routine
	RESTORE_ALL
	addl $4, %esp
	IRET

ENTRY(reserved_handler)//15
	SAVE_ALL
	call reserved_routine
	RESTORE_ALL
	IRET

ENTRY(floating_point_error_handler)//16
	SAVE_ALL
	call floating_point_error_routine
	RESTORE_ALL
	IRET

ENTRY(alignment_check_handler) //17
	SAVE_ALL
	call alignment_check_routine
	RESTORE_ALL
	addl $4, %esp
	IRET

//Interrupcions

ENTRY(clock_handler) //32
  SAVE_ALL
  call clock_routine
  EOI
  RESTORE_ALL
  IRET

ENTRY(keyboard_handler) //33
  SAVE_ALL
  call keyboard_routine
  EOI
  RESTORE_ALL
  IRET

//Syscalls

ENTRY(syscall_handler)
  SAVE_ALL
  cmpl $SYS_LENGHT, %eax
  jg syscall_wrong
  cmpl $0, %eax
  jge syscall_right

syscall_wrong:
  movl $-(ENOSYS), %eax
  jmp return

syscall_right:
  call *sys_call_table(, %eax, 0x04)

return:
  movl %eax, 24(%esp)
  RESTORE_ALL
  IRET
